#include "Block6.h"
#include "Game.h"

/**
 * 构造方法。
 */
Block6::Block6() {
    mBlocks[1][0].mUsed = mBlocks[1][1].mUsed = mBlocks[1][2].mUsed = mBlocks[2][0].mUsed = true;
}

/**
 * 擦除。
 */
void Block6::erase() {
    QRect rect;

    switch (mShape) {
        case ONE:
            rect.setRect(Const::GRID_SIZE * mLine, Const::GRID_SIZE * (mRow + 1), Const::GRID_SIZE * 3, Const::GRID_SIZE);
            Block::eraseRect(&rect);
            rect.setRect(Const::GRID_SIZE * mLine, Const::GRID_SIZE * (mRow + 2), Const::GRID_SIZE, Const::GRID_SIZE);
            Block::eraseRect(&rect);
            break;
        case TWO:
            rect.setRect(Const::GRID_SIZE * mLine, Const::GRID_SIZE * mRow, Const::GRID_SIZE, Const::GRID_SIZE);
            Block::eraseRect(&rect);
            rect.setRect(Const::GRID_SIZE * (mLine + 1), Const::GRID_SIZE * mRow, Const::GRID_SIZE, Const::GRID_SIZE * 3);
            Block::eraseRect(&rect);
            break;
        case THREE:
            rect.setRect(Const::GRID_SIZE * (mLine + 2), Const::GRID_SIZE * mRow, Const::GRID_SIZE, Const::GRID_SIZE);
            Block::eraseRect(&rect);
            rect.setRect(Const::GRID_SIZE * mLine, Const::GRID_SIZE * (mRow + 1), Const::GRID_SIZE * 3, Const::GRID_SIZE);
            Block::eraseRect(&rect);
            break;
        case FOUR:
            rect.setRect(Const::GRID_SIZE * (mLine + 1), Const::GRID_SIZE * mRow, Const::GRID_SIZE, Const::GRID_SIZE * 3);
            Block::eraseRect(&rect);
            rect.setRect(Const::GRID_SIZE * (mLine + 2), Const::GRID_SIZE * (mRow + 2), Const::GRID_SIZE, Const::GRID_SIZE);
            Block::eraseRect(&rect);
            break;
    }
}

/**
 * 获取底端所在的行数。底端是指方块最下方的有效格。
 * @return 底端所在的行数
 */
int Block6::getBottom() {
    if (mShape == THREE) {
        return mRow + 1;
    }
    return mRow + 2;
}

/**
 * 获取顶端所在的行数。顶端是指方块最上方的有效格。
 * @return 顶端所在的行数
 */
int Block6::getTop() {
    if (mShape == ONE) {
        return mRow + 1;
    }
    return mRow;
}

/**
 * 对不能下落的处理。
 */
void Block6::handleCannotMoveDown() {
    switch (mShape) {
        case ONE:
            Game::sExistentBlocks[mRow + 1][mLine].mUsed =
            Game::sExistentBlocks[mRow + 1][mLine + 1].mUsed =
            Game::sExistentBlocks[mRow + 1][mLine + 2].mUsed =
            Game::sExistentBlocks[mRow + 2][mLine].mUsed = true;
            Game::sExistentBlocks[mRow + 1][mLine].mColor =
            Game::sExistentBlocks[mRow + 1][mLine + 1].mColor =
            Game::sExistentBlocks[mRow + 1][mLine + 2].mColor =
            Game::sExistentBlocks[mRow + 2][mLine].mColor = mColor;
            break;
        case TWO:
            Game::sExistentBlocks[mRow][mLine].mUsed =
            Game::sExistentBlocks[mRow][mLine + 1].mUsed =
            Game::sExistentBlocks[mRow + 1][mLine + 1].mUsed =
            Game::sExistentBlocks[mRow + 2][mLine + 1].mUsed = true;
            Game::sExistentBlocks[mRow][mLine].mColor =
            Game::sExistentBlocks[mRow][mLine + 1].mColor =
            Game::sExistentBlocks[mRow + 1][mLine + 1].mColor =
            Game::sExistentBlocks[mRow + 2][mLine + 1].mColor = mColor;
            break;
        case THREE:
            Game::sExistentBlocks[mRow][mLine + 2].mUsed =
            Game::sExistentBlocks[mRow + 1][mLine].mUsed =
            Game::sExistentBlocks[mRow + 1][mLine + 1].mUsed =
            Game::sExistentBlocks[mRow + 1][mLine + 2].mUsed = true;
            Game::sExistentBlocks[mRow][mLine + 2].mColor =
            Game::sExistentBlocks[mRow + 1][mLine].mColor =
            Game::sExistentBlocks[mRow + 1][mLine + 1].mColor =
            Game::sExistentBlocks[mRow + 1][mLine + 2].mColor = mColor;
            break;
        case FOUR:
            Game::sExistentBlocks[mRow][mLine + 1].mUsed =
            Game::sExistentBlocks[mRow + 1][mLine + 1].mUsed =
            Game::sExistentBlocks[mRow + 2][mLine + 1].mUsed =
            Game::sExistentBlocks[mRow + 2][mLine + 2].mUsed = true;
            Game::sExistentBlocks[mRow][mLine + 1].mColor =
            Game::sExistentBlocks[mRow + 1][mLine + 1].mColor =
            Game::sExistentBlocks[mRow + 2][mLine + 1].mColor =
            Game::sExistentBlocks[mRow + 2][mLine + 2].mColor = mColor;
            break;
    }
}

/**
 * 下落。
 * @return 成功则返回 true，否则返回 false
 */
bool Block6::moveDown() {
    switch (mShape) {
        case ONE:
            if (mRow == 17) {
                this->handleCannotMoveDown();
                return false;
            }
            if (Game::sExistentBlocks[mRow + 3][mLine].mUsed ||
                Game::sExistentBlocks[mRow + 2][mLine + 1].mUsed ||
                Game::sExistentBlocks[mRow + 2][mLine + 2].mUsed) {
                this->handleCannotMoveDown();
                return false;
            }
            break;
        case TWO:
            if (mRow == 17) {
                this->handleCannotMoveDown();
                return false;
            }
            if (Game::sExistentBlocks[mRow + 1][mLine].mUsed ||
                Game::sExistentBlocks[mRow + 3][mLine + 1].mUsed) {
                this->handleCannotMoveDown();
                return false;
            }
            break;
        case THREE:
            if (mRow == 18) {
                this->handleCannotMoveDown();
                return false;
            }
            if (Game::sExistentBlocks[mRow + 2][mLine].mUsed ||
                Game::sExistentBlocks[mRow + 2][mLine + 1].mUsed ||
                Game::sExistentBlocks[mRow + 2][mLine + 2].mUsed) {
                this->handleCannotMoveDown();
                return false;
            }
            break;
        case FOUR:
            if (mRow == 17) {
                this->handleCannotMoveDown();
                return false;
            }
            if (Game::sExistentBlocks[mRow + 3][mLine + 1].mUsed ||
                Game::sExistentBlocks[mRow + 3][mLine + 2].mUsed) {
                this->handleCannotMoveDown();
                return false;
            }
            break;
    }

    return Block::moveDown();
}

/**
 * 左移。
 */
void Block6::moveLeft() {
    switch (mShape) {
        case ONE:
            if (mLine == 0) {
                return;
            }
            if (Game::sExistentBlocks[mRow + 1][mLine - 1].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine - 1].mUsed) {
                return;
            }
            break;
        case TWO:
            if (mLine == 0) {
                return;
            }
            if (Game::sExistentBlocks[mRow][mLine - 1].mUsed || 
                Game::sExistentBlocks[mRow + 1][mLine].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine].mUsed) {
                return;
            }
            break;
        case THREE:
            if (mLine == 0) {
                return;
            }
            if (Game::sExistentBlocks[mRow][mLine + 1].mUsed || 
                Game::sExistentBlocks[mRow + 1][mLine - 1].mUsed) {
                return;
            }
            break;
        case FOUR:
            if (mLine == -1) {
                return;
            }
            if (Game::sExistentBlocks[mRow][mLine].mUsed || 
                Game::sExistentBlocks[mRow + 1][mLine].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine].mUsed) {
                return;
            }
            break;
    }

    Block::moveLeft();
}

/**
 * 右移。
 */
void Block6::moveRight() {
    switch (mShape) {
        case ONE:
            if (mLine == 7) {
                return;
            }
            if (Game::sExistentBlocks[mRow + 1][mLine + 3].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine + 1].mUsed) {
                return;
            }
            break;
        case TWO:
            if (mLine == 8) {
                return;
            }
            if (Game::sExistentBlocks[mRow][mLine + 2].mUsed || 
                Game::sExistentBlocks[mRow + 1][mLine + 2].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine + 2].mUsed) {
                return;
            }
            break;
        case THREE:
            if (mLine == 7) {
                return;
            }
            if (Game::sExistentBlocks[mRow][mLine + 3].mUsed || 
                Game::sExistentBlocks[mRow + 1][mLine + 3].mUsed) {
                return;
            }
            break;
        case FOUR:
            if (mLine == 7) {
                return;
            }
            if (Game::sExistentBlocks[mRow][mLine + 2].mUsed || 
                Game::sExistentBlocks[mRow + 1][mLine + 2].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine + 3].mUsed) {
                return;
            }
            break;
    }

    Block::moveRight();
}

/**
 * 变形。
 */
void Block6::transform() {
    switch (mShape) {
        case ONE:
            if (mRow == -1) {
                return;
            }
            if (Game::sExistentBlocks[mRow][mLine].mUsed || 
                Game::sExistentBlocks[mRow][mLine + 1].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine + 1].mUsed) {
                return;
            }
            this->erase();
            mBlocks[1][0].mUsed = mBlocks[1][2].mUsed = mBlocks[2][0].mUsed = false;
            mBlocks[0][0].mUsed = mBlocks[0][1].mUsed = mBlocks[2][1].mUsed = true;
            mShape = TWO;
            break;
        case TWO:
            if (mLine == 8) {
                return;
            }
            if (Game::sExistentBlocks[mRow][mLine + 2].mUsed || 
                Game::sExistentBlocks[mRow + 1][mLine].mUsed || 
                Game::sExistentBlocks[mRow + 1][mLine + 2].mUsed) {
                return;
            }
            this->erase();
            mBlocks[0][0].mUsed = mBlocks[0][1].mUsed = mBlocks[2][1].mUsed = false;
            mBlocks[0][2].mUsed = mBlocks[1][0].mUsed = mBlocks[1][2].mUsed = true;
            mShape = THREE;
            break;
        case THREE:
            if (mRow == 18) {
                return;
            }
            if (Game::sExistentBlocks[mRow][mLine + 1].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine + 1].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine + 2].mUsed) {
                return;
            }
            this->erase();
            mBlocks[0][2].mUsed = mBlocks[1][0].mUsed = mBlocks[1][2].mUsed = false;
            mBlocks[0][1].mUsed = mBlocks[2][1].mUsed = mBlocks[2][2].mUsed = true;
            mShape = FOUR;
            break;
        case FOUR:
            if (mLine == -1) {
                return;
            }
            if (Game::sExistentBlocks[mRow + 1][mLine].mUsed || 
                Game::sExistentBlocks[mRow + 1][mLine + 2].mUsed || 
                Game::sExistentBlocks[mRow + 2][mLine + 2].mUsed) {
                return;
            }
            this->erase();
            mBlocks[0][1].mUsed = mBlocks[2][1].mUsed = mBlocks[2][2].mUsed = false;
            mBlocks[1][0].mUsed = mBlocks[1][2].mUsed = mBlocks[2][0].mUsed = true;
            mShape = ONE;
            break;
    }

    Block::draw();
}
